from math import sqrt

################################################################################
class Vector2D():
    """
    Class Vector2D - For Vector Mathematics 
        based on code by Matt Buckland (fup@ai-junkie.com)
    """
    ############################################################################
    def __init__(self, fX=0, fY=0):
        """
        Constructor
    
        param - fX : initial X co-ordinate
        param - fY : initial Y co-ordinate
        """
        self._fX = float(fX)
        self._fY = float(fY)
    ############################################################################
    
    ############################################################################
    def __add__(self, rOther):
        """
        Overrides + operator
        """
        if isinstance(rOther, Vector2D):
            # If we're adding another Vector...
            return Vector2D(self._fX + rOther.X(), self._fY + rOther.Y())
        else:
            # Otherwise we're ok as long as we have something with two values
            assert hasattr(rOther, '__len__') and len(rOther) == 2
            return Vector2D(self._fX + rOther[0], self._fY + rOther[1])
    ############################################################################
    
    __radd__ = __add__
    
    ############################################################################
    def __iadd__(self, rOther):
        """
        Overrides += operator
        """
        if isinstance(rOther, Vector2D):
            # If we're adding another Vector...
            self._fX += rOther.X()
            self._fY += rOther.Y()
        else:
            # Otherwise we're ok as long as we have something with two values
            assert hasattr(rOther, '__len__') and len(rOther) == 2
            self._fX += rOther[0]
            self._fY += rOther[1]
        return self
    ############################################################################
    
    ############################################################################
    def __sub__(self, rOther):
        """
        Overrides - operator with subject object on left side of equation
        """
        if isinstance(rOther, Vector2D):
            # If we're subtracting another Vector...
            return Vector2D(self._fX - rOther.X(), self._fY - rOther.Y())
        else:
            # Otherwise we're ok as long as we have something with two values
            assert hasattr(rOther, '__len__') and len(rOther) == 2
            return Vector2D(self._fX - rOther[0], self._fY - rOther[1])
    ############################################################################
    
    ############################################################################
    def __rsub__(self, rOther):
        """
        Overrides - operator with subject object on right side of equation
        """
        if isinstance(rOther, Vector2D):
            # If we're subtracting another Vector...
            return Vector2D(rOther.X() - self._fX, rOther.Y() - self._fY)
        else:
            # Otherwise we're ok as long as we have something with two values
            assert hasattr(rOther, '__len__') and len(rOther) == 2
            return Vector2D(rOther[0] - self._fX, rOther[1] - self._fY)
    ############################################################################
    
    ############################################################################
    def __isub__(self, rOther):
        """
        Overrides -= operator
        """
        if isinstance(rOther, Vector2D):
            # If we're adding another Vector...
            self._fX -= rOther.X()
            self._fY -= rOther.Y()
        else:
            # Otherwise we're ok as long as we have something with two values
            assert hasattr(rOther, '__len__') and len(rOther) == 2
            self._fX -= rOther[0]
            self._fY -= rOther[1]
        return self
    ############################################################################
    
    ############################################################################
    def __mul__(self, nOther):
        """
        Overrides * operator
        """
        # Need a single value
        assert type(nOther) in (int, float, long), "Value should be of type int, float or long"
        return Vector2D(self._fX * nOther, self._fY * nOther)
    ############################################################################
    
    __rmul__ = __mul__
    
    ############################################################################
    def __imul__(self, nOther):
        """
        Overrides *= operator
        """
        # Need a single value
        assert type(nOther) in (int, float, long), "Value should be of type int, float or long"
        self._fX *= nOther
        self._fY *= nOther
        return self
    ############################################################################
    
    ############################################################################
    def __div__(self, nOther):
        """
        Overrides / operator with subject object on left of equation
        """
        # Need a single value
        assert type(nOther) in (int, float, long)
        assert nOther not in 0
        return Vector2D(self._fX / nOther, self._fY / nOther)
    ############################################################################
    
    ############################################################################
    def __rdiv__(self, nOther):
        """
        Overrides / operator with subject object on right of equation
        """
        # Need a single value
        assert type(nOther) in (int, float, long)
        assert nOther not in 0
        return Vector2D(nOther / self._fX, nOther / self._fY)
    ############################################################################
    
    ############################################################################
    def __idiv__(self, nOther):
        """
        Overrides /= operator
        """
        # Need a single value
        assert type(nOther) in (int, float, long)
        self._fX /= nOther
        self._fY /= nOther
        return self
    ############################################################################
    
    ############################################################################
    # GetsNSets
    #
    def X(self): return self._fX
    def Y(self): return self._fY
    ############################################################################
    
    ############################################################################
    def Zero(self):
        """
        Zero - Sets X and Y to 0
        """
        self._fX = float(0)
        self._fY = float(0)
    ############################################################################
    
    ############################################################################
    def IsZero(self):
        """
        IsZero - Returns true if both X and Y are zero
        """
        if self._fX == 0 and self._fY == 0: return True
        return False
    ############################################################################
    
    ############################################################################
    def Length(self):
        """
        Length - Returns the length of the vector
        """
        return sqrt((self._fX * self._fX) + (self._fY * self._fY))
    ############################################################################
    
    ############################################################################
    def LengthSq(self):
        """
        LengthSq - Returns the squared length of the vector
        """
        return (self._fX * self._fX) + (self._fY * self._fY)
    ############################################################################
    
    ############################################################################
    def Dot(self, rVector2):
        """
        Dot - Returns the Dot Product between this and another Vector
        
        param - rVector2 : A second Vector object
        """
        return (self._fX * rVector2.X()) + (self._fY * rVector2.Y())
    ############################################################################
    
    ############################################################################
    def Sign(self, rVector2):
        """
        Sign - Returns 1 if second vector is clockwise of this vector, 
            -1 if anticlockwise
        
        param - rVector2 : A second Vector object
        """
        # Clockwise
        if (self._fY * rVector2.X() > self._fX * rVector2.Y()): return 1
        
        # Anti-clockwise
        return -1
    ############################################################################
    
    ############################################################################
    def Perp(self):
        """
        Perp - Returns a vector perpendicular to this one
        """
        return Vector2D(-self._fY, self._fX)
    ############################################################################
    
    ############################################################################
    def Distance(self, rVector2):
        """
        Distance - Calculates the euclidean distance between two vectors
        
        param - rVector2 : A second Vector object
        """
        YSeperation = float(rVector2.Y() - self._fY)
        XSeperation = float(rVector2.X() - self._fX)
        
        return sqrt((YSeperation*YSeperation) * (XSeperation*XSeperation))
    ############################################################################
    
    ############################################################################
    def DistanceSq(self, rVector2):
        """
        DistanceSq - Calculates the euclidean squared distance between two vectors
        
        param - rVector2 : A second Vector object
        """
        YSeperation = float(rVector2.Y() - self._fY)
        XSeperation = float(rVector2.X() - self._fX)
        
        return (YSeperation*YSeperation) * (XSeperation*XSeperation)
    ############################################################################
    
    ############################################################################
    def Truncate(self, nMax):
        """
        Truncate - Truncates the vector so that its length does not exceed max
        
        param - nMax : Maximum length
        """
        if(self.Length() > nMax):
            self.Normalize()
            self *= nMax
    ############################################################################
    
    ############################################################################
    def Reflect(self, rVector2):
        """
        Reflect - Given a normalized vector this method reflects the vector it is
            operating on
        
        param - rVector2 : A second Vector object
        """
        self += 2.0 * self.Dot(rVector2) * rVector2.GetReverse()
    ############################################################################
    
    ############################################################################
    def GetReverse(self):
        """
        GetReverse - Returns the vector that is the reverse of this vector
        """
        return Vector2D(-self._fX, -self._fY)
    ############################################################################
    
    ############################################################################
    def Normalize(self):
        """
        Normalize - Normalizes the vector
        """
        nLength = self.Length()
        
        if (nLength > 0):
            self._fX /= nLength
            self._fY /= nLength
    ############################################################################
################################################################################